package sketch.specs;

import java.util.List;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.internal.core.dom.NaiveASTFlattener;

import sketch.ast.ASTUtils;
import sketch.main.SketchTestOptions;
import sketch.util.Checker;

/**
 * This visitor need to expand Values.choose(), and the annotation!
 * */
public class SourceExpansionVisitor extends NaiveASTFlattener {
	
	public final Block wholeBlock;
	
	public final Block toReplacedBlock;
	
	public final Block newBlock;
	
	public SourceExpansionVisitor(Block wholeBlock, Block toReplacedBlock, Block newBlock) {
		this.wholeBlock = wholeBlock;
		this.toReplacedBlock = toReplacedBlock;
		this.newBlock = newBlock;
		Checker.checkTrue(ASTUtils.isNested(toReplacedBlock, wholeBlock), "To replaced block: \n" + toReplacedBlock
				+  "should be a partf the whole block: \n" + wholeBlock);
	}
	
	@Override
	public boolean visit(Block block) {
		Checker.checkTrue(block.getAST() == this.toReplacedBlock.getAST(), "The AST should be the same");
		if(block.getStartPosition() == this.toReplacedBlock.getStartPosition()) {
			//clear all statements in that block
			block.statements().clear();
			//copy every statements from the new block
			List<Statement> stmts = this.newBlock.statements();
			System.out.println("statement size: " + stmts.size());
			if(SketchTestOptions.verbose) {
			    System.out.println("size: " + stmts.size());
			}
			for(int i = 0; i < stmts.size(); i++) {
				Statement stmt = stmts.get(i);
				Statement stmt_copy = ASTUtils.deepClone(stmt);
				//stmt.delete();
				stmt_copy.delete();
				block.statements().add(stmt_copy);
			}
			//experimental
//			ASTNode node = block.getParent();
//			if(node instanceof Block) {
//				Block parentBlock = (Block)node;
//				int blockindex = parentBlock.statements().indexOf(block);
//				parentBlock.statements().remove(blockindex);
//				for(int j = 0; j < block.statements().size(); j++) {
//					Statement stmt = (Statement) block.statements().get(j);
//					stmt.delete();
//					parentBlock.statements().add(j + blockindex, stmt);
//				}
//			}
			
			//block.statements().addAll(this.newBlock.statements());//XXX could be some problems
			//here is the original implementation
			/*
			List<Statement> statements = this.newBlock.statements();
			for(Statement statement : statements) {
				//statement = ASTUtils.parseStatements(statement.toString());
				AST ast = statement.getAST();
				//XXX this approach is not eleganet, and will introduce new { and }
				Block newBlock = ast.newBlock();
				Statement s = ASTUtils.deepClone(statement);
				newBlock.statements().add(s);
				block.statements().add(newBlock);
			}
           */
			
			return false;
		}
		return super.visit(block);
	}
	
	public Block getReplacedBlock() {
		Block wholeNewBlock = ASTUtils.deepClone(this.wholeBlock);
		this.visit(wholeNewBlock);
		return wholeNewBlock;
	}
	
}
